package com.ojoin.trade.common.jedis.support;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Set;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.Reflection;

import redis.clients.jedis.Jedis;
import redis.clients.util.Pool;

public class JedisFactory<T> implements InitializingBean, DisposableBean, FactoryBean<T> {
	private Set<String> names = ImmutableSet.of("hashCode", "toString", "equals");

	private Class<T> clazz;

	private Pool<Jedis> pool = null;

	public Pool<Jedis> getPool() {
		return pool;
	}

	public void setPool(Pool<Jedis> pool) {
		this.pool = pool;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		
	}

	@Override
	public void destroy() throws Exception {

	}

	@SuppressWarnings("unchecked")
	public JedisFactory() {
		this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@Override
	public T getObject() throws Exception {
		return Reflection.newProxy(clazz, new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				if (names.contains(method.getName())) {
					Pool<Jedis> pool = getPool();
					return method.invoke(pool.getResource(), args);
				}

				Object ret = null;
				Pool<Jedis> pool = getPool();
				Jedis redis = pool.getResource();
				try {
					ret = method.invoke(redis, args);
					pool.returnResource(redis);
				} catch (Exception e) {
					pool.returnBrokenResource(redis);
					return null;
				}
				return ret;
			}
		});
	}

	@Override
	public Class<?> getObjectType() {
		return clazz;
	}

	@Override
	public boolean isSingleton() {
		return false;
	}

}
